/**
 * @file devfs.c
 * @author lcz (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-11-10
 *
 * @copyright Copyright (c) 2022
 *
 */

#include "fs/file.h"
#include "dev/dev.h"
#include "fs/devfs/devfs.h"
#include "tools/kilb.h"
// 设备文件系统中支持的设备
// 整个文件系统并非只有tty设备 我们建一个表来描述我们支持的设备信息
static devfs_type_t devfs_type_list[] = {
    {
        .name = "tty",
        .dev_type = DEV_TTY,
        .file_type = FILE_TTY,
    },
};

/**
 * @brief 挂载方法
 * @param fs 文件系统
 * @param major 主设备号
 * @param minor 次设备号
 */
int devfs_mount(fs_t *fs, int major, int minor)
{
    // fs结构体的上一层代码实现
    fs->type = FS_DEVFS;
}
/**
 * @brief 卸载
 * @param fs 文件系统
 * @param major 主设备号
 * @param minor 次设备号
 */
void devfs_unmount(fs_t *fs, int major, int minor)
{
}
/**
 * @brief 打开文件
 * 所有设备放在设备文件系统中进行管理
 * @param fs 文件系统
 * @param path 文件路径
 * @param file 文件指针
 */
int devfs_open(fs_t *fs, const char *path, file_t *file)
{

    // 遍历所有支持的设备类型列表，根据path中的路径，找到相应的设备类型
    for (int i = 0; i < sizeof(devfs_type_list) / sizeof(devfs_type_list[0]); i++)
    {
        devfs_type_t *type = devfs_type_list + i;
        // dev_type 就相当于主设备号了
        // 查找相同的名称，然后从中提取后续部分，转换成字符串
        int type_name_len = kernel_strlen(type->name);

        // 如果存在挂载点路径，则跳过该路径，取下级子目录
        if (kernel_strncmp(path, type->name, type_name_len) == 0)
        {
            int minor;
            // 次设备号
            // 转换得到设备子序号
            if ((kernel_strlen(path) > type_name_len) && (path_to_num(path + type_name_len, &minor)) < 0)
            {
                log_printf("Get device num failed. %s", path);
                break;
            }

            // 打开设备
            // 调用dev_open打开设备dev_open 调device_t 结构体的open回调函数打开，我们使用两层抽象回调函数实现
            // 对文件的抽象
            int dev_id = dev_open(type->dev_type, minor, (void *)0);
            if (dev_id < 0)
            {
                log_printf("Open device failed:%s", path);
                break;
            }

            // 纪录所在的设备号
            file->dev_id = dev_id;
            file->fs = fs; // file获取文件系统信息
            file->pos = 0;
            file->size = 0;
            file->type = type->file_type;
            return 0;
        }
    }

    return -1;
}
// 打开的时候传一个file结构，描述一个特定的打开文件,我们将fs_t 的信息放在file结构中
/**
 * @brief 设备读
 */
int devfs_read(char *buf, int size, file_t *file)
{
    // 获取设备id file结构中的dev_id
    return dev_read(file->dev_id, file->pos, buf, size);
}
/**
 * @brief 设备写
 */
int devfs_write(char *buf, int size, file_t *file)
{
    return dev_write(file->dev_id, file->pos, buf, size);
}
/**
 * @brief 关闭设备
 */
void devfs_close(file_t *file)
{
    dev_close(file->dev_id);
}
/**
 * @brief 调整文件指针
 */
int devfs_seek(file_t *file, uint32_t offset, int dir)
{
    return -1;
}
/**
 * @brief 获取文件信息
 */
int devfs_stat(file_t* file, struct stat *st)
{
    return -1;
}
/**
 * @brief 设备控制接口
 * @param file 文件
 * @param cmd 命令
 * @return * int 
 */
int devfs_ioctl(file_t *file, int cmd, int arg0, int arg1){
    return dev_control(file->dev_id, cmd, arg0, arg1);
}

// 设备文件系统的回调函数
fs_op_t devfs_op = {
    .mount = devfs_mount,
    .unmount = devfs_unmount,
    .open = devfs_open,
    .write = devfs_write,
    .close = devfs_close,
    .seek = devfs_seek,
    .stat = devfs_stat,
    .read = devfs_read,
    .ioctl = devfs_ioctl,
};
